package cn.sciento.starter.lock.service.impl;

import cn.sciento.starter.lock.LockInfo;
import cn.sciento.starter.lock.service.LockService;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class RedLockServiceImpl implements LockService {
  @Qualifier("lockRedissonClient")
  @Autowired
  private RedissonClient redissonClient;
  
  private final ThreadLocal<LockInfo> lockInfoThreadLocal = new ThreadLocal<>();
  
  public void setLockInfo(LockInfo lockInfo) {
    this.lockInfoThreadLocal.set(lockInfo);
  }
  
  public LockInfo getLockInfo() {
    return this.lockInfoThreadLocal.get();
  }
  
  public void clearLockInfo() {
    this.lockInfoThreadLocal.remove();
  }
  
  public boolean lock() {
    LockInfo lockInfo = this.lockInfoThreadLocal.get();
    RLock[] lockList = new RLock[lockInfo.getKeyList().size()];
    for (int i = 0; i < lockInfo.getKeyList().size(); i++)
      lockList[i] = this.redissonClient.getLock(lockInfo.getKeyList().get(i)); 
    try {
      RedissonRedLock lock = new RedissonRedLock(lockList);
      return lock.tryLock(lockInfo.getWaitTime(), lockInfo.getLeaseTime(), lockInfo.getTimeUnit());
    } catch (Exception e) {
      return false;
    } 
  }
  
  public void releaseLock() {
    LockInfo lockInfo = this.lockInfoThreadLocal.get();
    RLock[] lockList = new RLock[lockInfo.getKeyList().size()];
    for (int i = 0; i < lockInfo.getKeyList().size(); i++)
      lockList[i] = this.redissonClient.getLock(lockInfo.getKeyList().get(i)); 
    RedissonRedLock lock = new RedissonRedLock(lockList);
    lock.unlock();
    this.lockInfoThreadLocal.remove();
  }
}
